﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using TiffLibrary;

namespace WholeSlideImageViewer
{
    internal class TiffOutputDialogViewModel : ViewModelBase, ITiffOutputOptions
    {
        private readonly TileSizeOption[] _tileSizeOptions;
        private readonly FileCompression[] _compressionOptions;
        private readonly DeflateCompressionLevel[] _deflateLevelOptions;
        private readonly int[] _threadCountOptions;

        private TileSizeOption _tileSize;
        private FileCompression _compression;

        private bool _lzwUseDifferential;

        private bool _deflateUseDifferential;
        private DeflateCompressionLevel _deflateLevel;

        private bool _jpegOptimizeCoding;
        private bool _jpegUseSharedQuantizationTables;
        private bool _jpegUseSharedHuffmanTables;

        private int _threadCount;

        private ICommand? _confirmCommand;
        private ICommand? _cancelCommand;

        public event Action<ITiffOutputOptions>? RequestConfirm;
        public event Action? RequestCancel;

        public IEnumerable<TileSizeOption> TileSizeOptions => _tileSizeOptions;
        public IEnumerable<FileCompression> CompressionOptions => _compressionOptions;
        public IEnumerable<DeflateCompressionLevel> DeflateLevelOptions => _deflateLevelOptions;
        public IEnumerable<int> ThreadCountOptions => _threadCountOptions;

        public TileSizeOption TileSize { get => _tileSize; set => OnPropertyChanged(nameof(TileSize), ref _tileSize, value); }

        int ITiffOutputOptions.TileSize => _tileSize.TileSise;

        public FileCompression Compression { get => _compression; set => OnPropertyChanged(nameof(Compression), ref _compression, value); }

        TiffCompression ITiffOutputOptions.Compression => _compression.Compression;

        public bool LzwUseDifferential { get => _lzwUseDifferential; set => OnPropertyChanged(nameof(LzwUseDifferential), ref _lzwUseDifferential, value); }

        public bool DeflateUseDifferential { get => _deflateUseDifferential; set => OnPropertyChanged(nameof(DeflateUseDifferential), ref _deflateUseDifferential, value); }

        public DeflateCompressionLevel DeflateLevel { get => _deflateLevel; set => OnPropertyChanged(nameof(DeflateLevel), ref _deflateLevel, value); }

        int ITiffOutputOptions.DeflateCompressionLevel => _deflateLevel.Level;

        public bool JpegOptimizeCoding { get => _jpegOptimizeCoding; set => OnPropertyChanged(nameof(JpegOptimizeCoding), ref _jpegOptimizeCoding, value); }

        public bool JpegUseSharedQuantizationTables { get => _jpegUseSharedQuantizationTables; set => OnPropertyChanged(nameof(JpegUseSharedQuantizationTables), ref _jpegUseSharedQuantizationTables, value); }

        public bool JpegUseSharedHuffmanTables { get => _jpegUseSharedHuffmanTables; set => OnPropertyChanged(nameof(JpegUseSharedHuffmanTables), ref _jpegUseSharedHuffmanTables, value); }

        public int ThreadCount { get => _threadCount; set => OnPropertyChanged(nameof(ThreadCount), ref _threadCount, value); }

        public ICommand ConfirmCommand => _confirmCommand ??= new RelayCommand(_ => Confirm(), _ => true);

        public ICommand CancelCommand => _cancelCommand ??= new RelayCommand(_ => Cancel(), _ => true);

        public TiffOutputDialogViewModel()
        {
            _tileSizeOptions = new TileSizeOption[]
            {
                new TileSizeOption(64, "64"),
                new TileSizeOption(128, "128"),
                new TileSizeOption(256, "256 (推荐)"),
                new TileSizeOption(512, "512"),
                new TileSizeOption(1024, "1024"),
            };
            _tileSize = _tileSizeOptions[2]; // 256

            _compressionOptions = new FileCompression[]
            {
                new FileCompression(TiffCompression.NoCompression , "无压缩"),
                new FileCompression(TiffCompression.Lzw , "LZW"),
                new FileCompression(TiffCompression.Deflate , "Deflate"),
                new FileCompression(TiffCompression.Jpeg , "JPEG"),
            };
            _compression = _compressionOptions[3]; // JPEG

            _deflateLevelOptions = new DeflateCompressionLevel[]
            {
                new DeflateCompressionLevel(1, "1 (最快)"),
                new DeflateCompressionLevel(2, "2"),
                new DeflateCompressionLevel(3, "3"),
                new DeflateCompressionLevel(4, "4"),
                new DeflateCompressionLevel(5, "5 (默认)"),
                new DeflateCompressionLevel(6, "6"),
                new DeflateCompressionLevel(7, "7"),
                new DeflateCompressionLevel(8, "8"),
                new DeflateCompressionLevel(9, "9 (最好)"),
            };
            _deflateLevel = _deflateLevelOptions[5]; // 6

            _threadCountOptions = new int[] { 1, 2, 4, 8, 12, 16 };

            _lzwUseDifferential = true;

            _deflateUseDifferential = true;

            _jpegOptimizeCoding = false;
            _jpegUseSharedQuantizationTables = true;
            _jpegUseSharedHuffmanTables = false;

            _threadCount = 1;
        }

        public void Confirm()
        {
            RequestConfirm?.Invoke(this);
        }

        public void Cancel()
        {
            RequestCancel?.Invoke();
        }

        public class TileSizeOption
        {
            public TileSizeOption(int tileSise, string displayText)
            {
                TileSise = tileSise;
                DisplayText = displayText;
            }

            public int TileSise { get; set; }
            public string? DisplayText { get; set; }
        }

        public class FileCompression
        {
            public FileCompression(TiffCompression compression, string? displayText)
            {
                Compression = compression;
                DisplayText = displayText;
            }

            public TiffCompression Compression { get; set; }
            public string? DisplayText { get; set; }
        }

        public class DeflateCompressionLevel
        {
            public DeflateCompressionLevel(int level, string? displayText)
            {
                Level = level;
                DisplayText = displayText;
            }

            public int Level { get; set; }
            public string? DisplayText { get; set; }
        }
    }

    class CompressionToLzwOptionsVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType != typeof(Visibility))
            {
                throw new NotSupportedException();
            }
            if (value is TiffOutputDialogViewModel.FileCompression compression)
            {
                if (compression.Compression == TiffCompression.Lzw)
                {
                    return Visibility.Visible;
                }
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }

    class CompressionToDeflateOptionsVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType != typeof(Visibility))
            {
                throw new NotSupportedException();
            }
            if (value is TiffOutputDialogViewModel.FileCompression compression)
            {
                if (compression.Compression == TiffCompression.Deflate)
                {
                    return Visibility.Visible;
                }
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }

    class CompressionToJpegOptionsVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType != typeof(Visibility))
            {
                throw new NotSupportedException();
            }
            if (value is TiffOutputDialogViewModel.FileCompression compression)
            {
                if (compression.Compression == TiffCompression.Jpeg)
                {
                    return Visibility.Visible;
                }
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }

    class JpegOptimizeCodingToHuffmanOptionVisibilityConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (targetType != typeof(Visibility))
            {
                throw new NotSupportedException();
            }
            if (value is bool optimizeCoding)
            {
                return optimizeCoding ? Visibility.Collapsed : Visibility.Visible;
            }
            return Visibility.Collapsed;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}
